<?php

declare(strict_types=1);

namespace App\Common\Dto;

use ReflectionClass;

abstract class DataObject
{
    /**
     * 转换对象为数组，包括私有属性
     *
     * @return array
     */
    public function toArray(): array
    {
        $array = [];
        $reflection = new ReflectionClass($this);

        foreach ($reflection->getProperties() as $property) {
            $property->setAccessible(true);
            $name = $property->getName();
            $value = $property->getValue($this);

            if (is_object($value) && method_exists($value, 'toArray')) {
                $array[$name] = $value->toArray();
            } elseif (is_array($value)) {
                $array[$name] = $this->processArray($value);
            } else {
                $array[$name] = $value;
            }
        }

        return $array;
    }

    /**
     * 递归处理数组，将数组中的对象转换为数组
     *
     * @param array $array
     * @return array
     */
    private function processArray(array $array): array
    {
        return array_map(function ($item) {
            if (is_object($item) && method_exists($item, 'toArray')) {
                return $item->toArray();
            } elseif (is_array($item)) {
                return $this->processArray($item);
            }
            return $item;
        }, $array);
    }

    /**
     * 从数组填充属性（静态工厂方法）
     *
     * @param array $data
     * @return static
     */
    public static function fromArray(array $data): static
    {
        $instance = new static();
        $reflection = new ReflectionClass($instance);

        foreach ($data as $key => $value) {
            $property = $reflection->getProperty($key);

            if ($property) {
                $property->setAccessible(true);
                $property->setValue($instance, $value);
            }
        }

        return $instance;
    }
}